package com.oazon.moco.serialport.core;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;

import com.oazon.common.Logger;
import com.oazon.common.util.Utils;

public class Pack  implements Serializable {

	private static String TAG = "Pack";
	private static final long serialVersionUID = -9025275559686764510L;
	private byte header;
	private byte type;//类型
	private int len=0;//长度
	private byte[] data;//数据
	private byte check;
	
	public byte getHeader() {
		return header;
	}

	public void setHeader(byte header) {
		this.header = header;
	}

	public byte getCheck() {
		return check;
	}

	public void setCheck(byte check) {
		this.check = check;
	}

	public byte getType() {
		return type;
	}

	public void setType(byte type) {
		this.type = type;
	}

	public int getLen() {
		return len;
	}

	public void setLen(int len) {
		this.len = len;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}

	//byte 数组与 int 的相互转换  
    public static int byteArrayToInt(byte[] b) {  
        return   b[3] & 0xFF |  
                (b[2] & 0xFF) << 8 |  
                (b[1] & 0xFF) << 16 |  
                (b[0] & 0xFF) << 24;  
    }  
    
  //byte 数组与 short 的相互转换  
    public static short byteArrayToShort(byte[] b) {  
        return   (short)(b[1] & 0xFF |  
                (b[0] & 0xFF) <<8);  
    }  
  
    public static byte[] intToByteArray(int a) {  
        return new byte[] {  
            (byte) ((a >> 24) & 0xFF),  
            (byte) ((a >> 16) & 0xFF),     
            (byte) ((a >> 8) & 0xFF),     
            (byte) (a & 0xFF)  
        };  
    }  
	/** 
     * 将int数值转换为占四个字节的byte数组，本方法适用于(高位在前，低位在后)的顺序.  和bytesToInt2（）配套使用
     */  
	public static byte[] intToBytes2(int value) 
	{ 
		byte[] src = new byte[2];
		
		src[0] = (byte) ((value>>8)&0xFF);
		src[1] = (byte) (value & 0xFF);		
		return src;
	}
	
	/** 
     * 将int数值转换为占四个字节的byte数组，本方法适用于(低位在前，高位在后)的顺序。 和bytesToInt（）配套使用
     * @param value 
     *            要转换的int值
     * @return byte数组
     */  
	public static byte[] intToBytes_L( int value ) 
	{ 
		byte[] src = new byte[4];
		src[3] =  (byte) ((value>>24) & 0xFF);
		src[2] =  (byte) ((value>>16) & 0xFF);
		src[1] =  (byte) ((value>>8) & 0xFF);  
		src[0] =  (byte) (value & 0xFF);				
		return src; 
	}
	 /** 
     * 将int数值转换为占四个字节的byte数组，本方法适用于(高位在前，低位在后)的顺序。  和bytesToInt2（）配套使用
     */  
	public static byte[] intToBytes_H(int value) 
	{ 
		byte[] src = new byte[4];
		src[0] = (byte) ((value>>24) & 0xFF);
		src[1] = (byte) ((value>>16)& 0xFF);
		src[2] = (byte) ((value>>8)&0xFF);  
		src[3] = (byte) (value & 0xFF);		
		return src;
	}	
	
	
	public static byte[] getEQ(int[] eq_h,int[] eq_l){
		ByteBuffer buffer=ByteBuffer.allocate((eq_h.length+eq_l.length)*4);
	      for(int eqh:eq_h)
	        	 buffer.put(intToBytes_H(eqh));
		  for(int eql:eq_l)
			    buffer.put(intToBytes_H(eql));
		return buffer.array();	
	}
	
	
	
	
	
	
	
	/**
	  *将32位的int值放到4字节的里
	  * @param num
	  * @return
	  */
	public static byte[] int2byteArray(int num) {
	   byte[] result = new byte[4];
	   result[0] = (byte)(num >>> 24);//取最高8位放到0下标
	   result[1] = (byte)(num >>> 16);//取次高8为放到1下标
	   result[2] = (byte)(num >>> 8); //取次低8位放到2下标
	   result[3] = (byte)(num );      //取最低8位放到3下标
	   return result;
	}

	/**
	  * 将4字节的byte数组转成一个int值
	  * @param b
	  * @return
	  */
	public static int byteArray2int(byte[] b){
	    byte[] a = new byte[4];
	    int i = a.length - 1,j = b.length - 1;
	    for (; i >= 0; i--,j--) {//从b的尾部(即int值的低位)开始copy数据
	        if(j >= 0)
	            a[i] = b[j];
	        else
	            a[i] = 0;//如果b.length不足4,则将高位补0
	  }
	    int v0 = (a[0] & 0xff) << 24;//&0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
	    int v1 = (a[1] & 0xff) << 16;
	    int v2 = (a[2] & 0xff) << 8;
	    int v3 = (a[3] & 0xff) ;
	    return v0 + v1 + v2 + v3;
	}
	
	/*
	 * byte为一位数的时候用
	 */
	public static int readOne(byte[] b){
		int a=-1;
		DataInputStream dis=new DataInputStream(new ByteArrayInputStream(b));
		try {
			 a=dis.readByte();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;	
	}
	/*
	 * 1,2时候用
	 */
	public static int[] readOneTwo(byte[] b){
		int[]  a=new int[2];
		DataInputStream dis=new DataInputStream(new ByteArrayInputStream(b));
		try {
			a[0]=dis.readByte();
			a[1]=dis.readShort();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;	
	}
	
	/*
	 * 2,2时候用
	 */
	public static int[] readTwoTwo(byte[] b){
		int[]  a=new int[2];
		DataInputStream dis=new DataInputStream(new ByteArrayInputStream(b));
		try {
			a[0]=dis.readShort();
			a[1]=dis.readShort();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;	
	}
	/*
	 * 1,2,2时候用
	 */
	public static int[] readOneTwoTwo(byte[] b){
		int[]  a=new int[3];
		DataInputStream dis=new DataInputStream(new ByteArrayInputStream(b));
		try {
			a[0]=dis.readByte();
			a[1]=dis.readShort();
			a[2]=dis.readShort();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;	
	}
	
	/*
	 * 应答码时候用
	 */
	public static String answer(byte[] b){
		String a=null;
		DataInputStream dis=new DataInputStream(new ByteArrayInputStream(b));
		try {
			a=dis.readByte()==1?"OK":"Error";
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;	
	}
	
    /*
	 * 接收包，如果type类型 为0x00就是应答包，如果不是就是正常 的包
	 */
	
	public  Pack  getPack(InputStream is) throws IOException, BadPackageException {

		Pack p=new Pack();
		ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
		DataInputStream dis = new DataInputStream(is);
		header = dis.readByte();
	    if (header != (byte) 0x5A) {
			throw new BadPackageException("wrong synchronize header."+header);
		}
	    
	    type = dis.readByte();
	    /*if(type==(byte)0x00){
			p.setType(type);
	    	data[0]=dis.readByte();
	    	p.setData(data);
	    	check=dis.readByte();
	    	p.setCheck(check);
	    }else*/{
	    	p.setType(type);
			len = dis.readShort();
			p.setLen(len);
			int remaining = len;
			byte[] buf = new byte[1024];
			while (remaining > 0) {
				int c = dis.read(buf, 0, remaining > 1024 ? 1024 : remaining);
				outputStream.write(buf, 0, c);
				remaining -= c;
			}
			p.setData(outputStream.toByteArray());
	    }
			return p;
	}

	/*
	 * 打包，如果type为0x00就是应答包,如果不是就是正常 的包，目前应答包已经去掉
	 */
	public byte[] tobytes(){
		len = 0;
		header=(byte)0x5A;
	    ByteBuffer b=null;
	    
		/*if(type==(byte)0x00){
			b=ByteBuffer.allocate(3);
			b.put(header);
			b.put(type);
			b.put(data);
		}else*/
	    {
			 
			 if(type==(byte)0x09){
				 len=getData().length+1;
			 }else{
				    if(getData()!=null&&getData().length>0){
						len=getData().length;
					}else
					{
						len=0;
					}
			 }
			
			 b=ByteBuffer.allocate(len+4);
			
	         b.put(header);//头
	    	 b.put(type);//类型
	    	
	 	   	 b.put(intToBytes2(len));//长度
	
			 if(getData()!=null&&getData().length>0){
				 b.put(getData());
			 }		
			 
			 //Log.i("testindex",String.valueOf(len));
			 if(type==(byte)0x09){
				 check=CRC8.calcCrc8(b.array());
				/* Logger.d(TAG,String.valueOf(check));
				 Logger.d(TAG,String.valueOf(b.array().length));*/
				 b.put(check);//校验码
			 }
		}
		byte[] result = b.array();
		Logger.d(TAG,""+Utils.toHex(result,','));
		return result;	 
		 
	}
	
	
	/**
     * DOC 从文件里读取数据.
     * 
     * @throws FileNotFoundException
     * @throws IOException
     */
  
	private static byte[] readEQFile(String filepath)  {
     String str = "";// 用来将每次读取到的字符拼接，当然使用StringBuffer类更好
       try {
		    File file = new File(filepath);// 指定要读取的文件
	        FileReader reader = new FileReader(file);// 获取该文件的输入流
	        char[] bb = new char[2];// 用来保存每次读取到的字符
	        int n;// 每次读取到的字符长度
	        while ((n = reader.read(bb)) != -1) {
	            str = new String(bb, 0, n)+"'"+str;
	        }
	        reader.close();// 关闭输入流，释放连接
		} catch (FileNotFoundException  e) {
			e.printStackTrace();
		}catch (IOException e) {
			e.printStackTrace();
		}
       String[] strs=getArray(str.split("\'"));
       byte[] mybytes=new byte[strs.length];
       for(int i=0;i<strs.length;i++){
    	  	  mybytes[i]=(byte)Integer.parseInt(strs[i]);
       }
       return mybytes;
    }
    /** 
     * 处理数组反转 
     * @param array 
     * @return 
     */  
    public static String[] getArray(String[] array) {  
    	String t[] = new String[array.length]; // 开辟一个新的数组   
    	int count = t.length - 1;  
        for (int x = 0; x < t.length; x++) {  
            t[count] = array[x]; // 数组反转   
            count--;  
        }  
        return t;  
    }  
	
	
	public static final byte[] input2byte(InputStream inStream)
			throws IOException {
		ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
		byte[] buff = new byte[100];
		int rc = 0;
		while ((rc = inStream.read(buff, 0, 100)) > 0) {
			swapStream.write(buff, 0, rc);
		}
		byte[] in2b = swapStream.toByteArray();
		return in2b;
	}
	
	@Deprecated
	//just for test
	public static void main(String[] args) {
		
		Pack p=new Pack();
	    byte [] bb=new byte[200];
	    for (int i=0;i<200;i++){
		  bb[i]=(byte) i;
	    }
			
		p.setType((byte)0x01);
		p.setData(bb);
	
		System.out.println(p);
			
		byte[] by=p.tobytes();
		System.out.println(by.length);
			
		for(byte pk:by)
			System.out.print(" "+pk);
		System.out.println();
		byte[] bx=new byte[2];
		bx[0]=by[1];
		bx[1]=by[2];
		System.out.println(bytesToInt3(bx,0));

	}
	
	public static int bytesToInt3(byte[] src, int offset) {
		int value;	
		value = (int) 
				((src[offset] & 0xFF)<<8)
				|(src[offset+1] & 0xFF);

		if(((src[offset] & 0xFF)<<8)>=1&&(src[offset+1] & 0xFF)<0){
			
			value=(int)	((src[offset] & 0xFF)<<8)
					|(src[offset+1] & 0xFF)+256;
		}
		return value;
	}


	
}

class CRC8 {
	static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188, (byte) 226, (byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194, (byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253, (byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33, (byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30, (byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96, (byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159, (byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160, (byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128, (byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2, (byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61, (byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29, (byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24,
			(byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155, (byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102, (byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219, (byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228, (byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251, (byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101, (byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184, (byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69, (byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248, (byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199, (byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134, (byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185, (byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237,
			(byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242, (byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205, (byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112, (byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141, (byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14, (byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77, (byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109, (byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82, (byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142, (byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177, (byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145, (byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148, (byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23, (byte) 73, (byte) 8,
			(byte) 86, (byte) 180, (byte) 234, (byte) 105, (byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235, (byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212, (byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244, (byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183, (byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52, (byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201, (byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116, (byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75, (byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10, (byte) 84, (byte) 215, (byte) 137, (byte) 107, 53 };

	/**
	 * 计算数组的CRC8校验值
	 * 
	 * @param data
	 *            需要计算的数组
	 * @return CRC8校验值
	 */
	public static byte calcCrc8(byte[] data) {
		return calcCrc8(data, 0, data.length, (byte) 0);
	}

	/**
	 * 计算CRC8校验值
	 * 
	 * @param data
	 *            数据
	 * @param offset
	 *            起始位置
	 * @param len
	 *            长度
	 * @return 校验值
	 */
	public static byte calcCrc8(byte[] data, int offset, int len) {
		return calcCrc8(data, offset, len, (byte) 0);
	}

	/**
	 * 计算CRC8校验值
	 * 
	 * @param data
	 *            数据
	 * @param offset
	 *            起始位置
	 * @param len
	 *            长度
	 * @param preval
	 *            之前的校验值
	 * @return 校验值
	 */
	public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
		byte ret = preval;
		for (int i = offset; i < (offset + len); ++i) {
			ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
		}
		return ret;
	}

	/*
	 * 校验是否成功
	 */
	
	public static boolean check(byte b){
		for(byte bb:crc8_tab){
			if(bb==b)
				return true;
		}
		return false;
	}
}